home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIX 6.5 Applications 2002 November
/
SGI IRIX 6.5 Applications 2002 November.iso
/
dev
/
insight_dev.idb
/
usr
/
share
/
Insight
/
bin
/
gifcomment.z
/
gifcomment
Wrap
Text File
|
2002-10-15
|
9KB
|
344 lines
#!/usr/bin/perl5
# Copyright 2002, Silicon Graphics, Inc.
# All Rights Reserved.
#
# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
# the contents of this file may not be disclosed to third parties, copied or
# duplicated in any form, in whole or in part, without the prior written
# permission of Silicon Graphics, Inc.
#
# RESTRICTED RIGHTS LEGEND:
# Use, duplication or disclosure by the Government is subject to restrictions
# as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
# and Computer Software clause at DFARS 252.227-7013, and/or in similar or
# successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
# rights reserved under the Copyright Laws of the United States.
##########################################################################
#
# Read and set comments in a GIF file
#
# http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
#
# Version 1.0 - 12/3/01
#
##########################################################################
# Global array to store existing comment information
@g_comments = ();
undef $new_comment;
$gif_file = '';
while($arg = shift(@ARGV)) {
if($arg eq '-c') {
$new_comment = shift(@ARGV);
} elsif($arg eq '-h') {
ShowUsage();
exit;
} elsif($arg =~ m#^-#) {
print STDERR "Unknown argument '$arg'\n\n";
ShowUsage();
exit(1);
} else {
$gif_file = $arg;
last;
}
}
if($gif_file eq '') {
ShowUsage();
exit(1);
} elsif(! -e $gif_file) {
print STDERR "GIF file '$gif_file' doesn't exist.\n\n";
ShowUsage();
exit(1);
}
open(GIF, $gif_file) || die "Can't open '$gif_file'\n";
my(%info) = ReadFileHeader();
SkipColorMap($info{'color_map_size'}) if($info{'global_colormap'} == 1);
my($image_start) = FindImageDescriptorAndComments();
close(GIF);
if(defined($new_comment)) {
InsertComment($gif_file, $new_comment, $image_start, @g_comments);
} else {
ShowComments(@g_comments);
}
##########################################################################
#
# The Header of the file contains two 3 byte fields.
# Bytes 0-2 - 'GIF' (GIF file identifier)
# Bytes 3-5 - version number (either '87a' or '89a')
#
# The Logical Screen Descriptor is located directly after the Header.
# It is a seven byte block orginized as:
#
# Bytes 0 & 1 - width (16 bit little-endian)
# Bytes 2 & 3 - height (16 bit little-endian)
# Byte 4 - four fields packed together
# 1 bit - Global Color Table Flag (bit 7)
# 3 bits - Color Resolution
# 1 bit - Sort Flag
# 3 bits - Size of the Global Color Table (bits 0-2)
# Byte 5 - Background Color Index
# Byte 6 - Pixel Aspect Ratio
#
# Returns a hash table with fields for each piece of information found.
#
##########################################################################
sub ReadFileHeader {
my($tmp, $tmp_packed) = '';
my(%info) = ();
read(GIF, $tmp, 3);
if($tmp ne 'GIF') {
die "This is not a GIF file.\n";
}
read(GIF, $tmp, 3);
if($tmp ne '87a' && $tmp ne '89a') {
die "The version '$tmp' is invalid for a GIF file.\n";
}
$info{'version'} = $tmp;
# height and width are 2 byte (16 bit little-endian) numbers
read(GIF, $tmp, 2);
$info{'width'} = unpack("v", $tmp);
read(GIF, $tmp, 2);
$info{'height'} = unpack("v", $tmp);
read(GIF, $tmp, 1);
$tmp_packed = unpack("C", $tmp);
$info{'color_map_size'} = 2 << ($tmp_packed & 0x07);
$info{'sort_flag'} = ($tmp_packed & 0x08) >> 3;
$info{'color_res'} = (($tmp_packed & 0x70) >> 3) + 1;
$info{'global_colormap'} = ($tmp_packed & 0x80) >> 7;
read(GIF, $tmp, 1);
$info{'background'} = unpack("C", $tmp);
read(GIF, $tmp, 1);
$info{'aspect_ratio'} = unpack("C", $tmp);
return(%info);
}
##########################################################################
#
# Ignore the portion of the GIF file where the colormap is listed
#
# $colormap_size - number of colors described with RGB triplets (3 bytes)
#
##########################################################################
sub SkipColorMap {
my($colormap_size) = @_;
# RGB triplets are used to describe each color
read(GIF, $tmp, 3 * $colormap_size);
}
##########################################################################
#
# Process the remainder of the file before the image data starts. This
# is where any comments should be located in the file. According to the
# GIF spec, comment blocks could occur after the image data, but for the
# purpose of this program they can be ignored.
#
# Returns the location in the file where the image data begins.
#
##########################################################################
sub FindImageDescriptorAndComments {
my($image_start) = 0;
# or set to tell(GIF) right now
while(read(GIF, $c, 1)) {
$c_ord = ord($c);
if($c_ord == 0x3B) {
# GIF terminator (end of file)
last;
} elsif($c_ord == 0x21) {
ProcessExtension();
next;
} elsif($c_ord == 0x2C) {
# Start of the image descriptor
$image_start = tell(GIF) - 1;
last;
} else {
print "Unknown char [$c][$c_ord]\n";
next;
}
}
return($image_start)
}
##########################################################################
#
# Process GIF comment extension blocks and ignore all others. Comments
# that are found will be added to the @g_comments array as a string with
# three colon separated fields fields.
#
# comment_start_offset:comment_length:comment_text
#
##########################################################################
sub ProcessExtension {
my($label, $comment, $comment_segment) = '';
my($start, $length) = 0;
read(GIF, $label, 1);
if(ord($label) == 0xFE) {
# Comment extension
$start = tell(GIF) - 2;
while(GetDataBlock(\$comment_segment)) {
$comment .= $comment_segment;
}
$length = tell(GIF) - $start;
push(@g_comments, "$start:$length:$comment");
} else {
# Ignore other extension types
# Graphic Control Extension - 0xF9
# Plain Text Label - 0x01
# Application Extension - 0xFF
while(GetDataBlock()) {};
}
}
##########################################################################
#
# Data blocks begin with a single byte which is the length of the
# data contained in the block. Any data read will be stored in the
# $buffer_ref parameter reference passed to this routine. If the
# incorrect amount of data is read, the program will exit.
#
# Returns the number of bytes of data read. 0 will be returned for
# an empty data block.
#
##########################################################################
sub GetDataBlock {
my($buffer_ref) = @_;
my($size) = 0;
read(GIF, $size, 1);
$size = ord($size);
return(0) if($size == 0);
if(read(GIF, $$buffer_ref, $size) != $size) {
die "Error reading data block.\n";
} else {
return($size);
}
}
##########################################################################
#
# Insert a new comment into the GIF file. Any existing comments will
# be overwritten. The main steps used are:
# 1. Read the entire GIF file into a string
# 2. Strip out existing comments
# 3. Print out the GIF up to the start of the image data
# 4. Print out the new comment
# 5. Print the remainder of the image data
#
##########################################################################
sub InsertComment {
my($file, $comment, $image_start, @existing_comments) = @_;
open(GIF_IN, "$file") || die "Can't open '$file'\n";
my($f) = join('', <GIF_IN>);
close(GIF_IN);
# Remove existing comments
foreach my $info (reverse(@existing_comments)) {
my($start, $length, $old_comment) = split(/:/, $info, 3);
substr($f, $start, $length) = "";
$image_start -= $length;
}
open(GIF_OUT, ">$file") || die "Can't write to '$file'\n";
# Print the file to the point where the comment is inserted
print GIF_OUT substr($f, 0, $image_start);
if($comment ne '') {
# Add the comment
# First print comment extension block identifier
print GIF_OUT pack("c", 0x21);
print GIF_OUT pack("c", 0xFE);
# Break up comment into maximum 254 byte data block chunks
while(length($comment) > 254) {
print GIF_OUT pack("c", 254);
print GIF_OUT substr($comment, 0, 254);
$comment = substr($comment, 254);
}
# Print remainder of the comment
print GIF_OUT pack("c", length($comment));
print GIF_OUT $comment;
# Terminating empty data block for the comment
print GIF_OUT pack("c", 0x00);
}
# Print the remainder of the image
print GIF_OUT substr($f, $image_start);
close(GIF_OUT);
}
##########################################################################
#
# Display any comments found
#
##########################################################################
sub ShowComments {
my(@comments) = @_;
foreach my $info (@comments) {
my($start, $length, $comment) = split(/:/, $info, 3);
print "$comment\n";
}
}
##########################################################################
#
# Display usage information
#
##########################################################################
sub ShowUsage {
my($name) = $0;
$name =~ s#^.*/([^/]+)$#$1#;
print <<USAGE;
Usage: $name [-h] [-c comment] file
-h = Print this usage statement
-c = Specify a comment string to add to the GIF file
With no options, any existing comments will be shown. When a new comment
is specified, all existing comments will be overwritten.
USAGE
}